const nsIglPHProxy = Components.interfaces.nsIglPHProxy;
const nsISupports = Components.interfaces.nsISupports;
const CLASS_ID = Components.ID("{4927cb59-fe47-40a6-8922-5dbff9b0b45f}");
const CLASS_NAME = "A PHProxy of Gladder";
const CONTRACT_ID = "@gladder.gneheix.com/phproxy;1";
const ALPHA1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const ALPHA2 = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
const CC = Components.classes;
const CI = Components.interfaces;
const GL_PHPROXY_STATUS_FIALED_TO_CONNECT = -2;
const GL_PHPROXY_STATUS_NOT_WORKING = -3;
const GL_PHPROXY_STATUS_UNKNOWN = -1;

function PHProxy() {
	CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService).addObserver(this, "gl-network-status", false);
};

PHProxy.prototype = {
	_domain: null,
	_response: GL_PHPROXY_STATUS_UNKNOWN,
	_speed: 'unknown',
	_timeStartTest: null,
	
	get domain(){return this._domain},
	set domain(aDomain){this._domain = aDomain;
		if (this._domain){
			this.testSpeed();
		}
	},
	get response(){return this._response},
	get speed(){return this._speed},
	
	proxy: function(url) {
		try{
			return "http://"+this._domain+"/index.php?hl=f5&q=" + encodeURIComponent(this._rot13(url));
		}catch(e){}
	},
	
	unproxy: function(url){
		try{
			var u = url.replace(new RegExp("http\\:\\/\\/([\\w-]+\\.)*"+this._domain.replace(/([\-\.])/g, "\\$1")), "");
			if (u.indexOf("http://") != 0){
				u = u.replace(/.*[\?\&]q\=([^\&]+).*/, "$1");
				if (u.indexOf("uggc%3A%2F%2F") == 0){
					return this._rot13_back(decodeURIComponent(u));
				}
				if (u.indexOf("uggc%3N%2S%2S") == 0){
					return decodeURIComponent(this._rot13_back(u));
				}
				if (u.indexOf("uggc%253A%252F%252F") == 0){
					return this._rot13_back(decodeURIComponent(decodeURIComponent(u)));
				}
				if (u.indexOf("uggc%253N%252S%252S") == 0){
					return decodeURIComponent(this._rot13_back(decodeURIComponent(u)));
				}
			}
		}catch(e){}
		return url;
	},

	_rot13: function (str) {
		var newStr = "";
		var curLet, curLetLoc;
		for (var i = 0; i < str.length; i++) {
			curLet = str.charAt(i);
			curLetLoc = ALPHA1.indexOf(curLet);
			newStr += (curLetLoc < 0) ? curLet : ALPHA2.charAt(curLetLoc);
		}
		return newStr;
	},
	_rot13_back: function(str) {
		var newStr = "";
		var curLet, curLetLoc;
		for (var i = 0; i < str.length; i++) {
			curLet = str.charAt(i);
			curLetLoc = ALPHA2.indexOf(curLet);
			newStr += (curLetLoc < 0) ? curLet : ALPHA1.charAt(curLetLoc);
		}
		return newStr;
	},
	_setResponse: function(re){
		this._response = re;
		this._speed = this._response>0?this._response>30?"slow":"fast":"error";
		CC["@mozilla.org/observer-service;1"].
			getService(CI.nsIObserverService).
			notifyObservers(this, "gl-phproxy-speed", re);
		dump("glPHProxy ["+this.domain+"] testing result:" + re+"\n");
	},
	testSpeed : function () {
		if (this._response == GL_PHPROXY_STATUS_UNKNOWN){
			this._setTimer(5);
			try {
			    var ioService = CC["@mozilla.org/network/io-service;1"].createInstance(CI.nsIIOService);
			    if (ioService.offline){
			    	return;
			    }
			    var uri = ioService.newURI(this.proxy("http://www.yahoo.com"), null, null);
			    var channel = ioService.newChannelFromURI(uri);
			    
			    this._timeStartTest = new Date();
			    channel.asyncOpen(new this.observer(this), null);
			}
			catch (e) {dump("glPHProxy ["+this.domain+"]testing error: "+e+e.description+"\n")}
		}
	},
  _callback: function(aData, aRequest)
  {
    var httpChannel = aRequest.QueryInterface(CI.nsIHttpChannel);
    
    var network = true;
    var status = null;
    var statusText = null;
    
    try {
      // Get HTTP response
      status = httpChannel.responseStatus;
      statusText = httpChannel.responseStatusText;
    } catch (e) {
      network = false;
    }
    if (!network) // Network was disconnected
    {
		this._setResponse(GL_PHPROXY_STATUS_FIALED_TO_CONNECT);
      return;
    }
    else if (status == null || status != 200) 
    {
  		this._setResponse(GL_PHPROXY_STATUS_NOT_WORKING);
      return;
    }
    else if (aData.indexOf("Yahoo!") == -1){
  		this._setResponse(GL_PHPROXY_STATUS_NOT_WORKING);
      return;
    }
    else{
    	this._setResponse(Math.round(((new Date())-this._timeStartTest)/1000))
    }
  },
    _setTimer: function(minutes)
  {
    if (this._timer) {
      this._timer.cancel();
      this._timer = null;
    }
    
    if (minutes > 0) {
      try {
        this._interval = minutes;
        this._timer = GM_CC["@mozilla.org/timer;1"].createInstance(GM_CI.nsITimer);
        this._timer.initWithCallback(this, minutes * 60000, this._timer.TYPE_ONE_SHOT);
      } catch(e) {}
    }
  },
	observe: function(aSubject, aTopic, aData){
		if (aTopic == "gl-network-status"){
			try{
				if (aData == "true" && this._response < GL_PHPROXY_STATUS_UNKNOWN){
					this._response = GL_PHPROXY_STATUS_UNKNOWN;
					this.testSpeed();
				}
			}catch(e){}
		}
	},
  
  notify: function(aTimer)
  {
      this.testSpeed();
  },
  observer: function(aThis)
  {
    return ({
      _myData: "",
      
      onStartRequest: function(aRequest, aContext) {
        this._myData = "";
      },
      
      onStopRequest: function(aRequest, aContext, aStatus) {
        aThis._callback(this._myData, aRequest);
      },
      
      onDataAvailable: function(aRequest, aContext, aStream, aSourceOffset, aLength) {
        var scriptableInputStream = CC["@mozilla.org/scriptableinputstream;1"].createInstance(CI.nsIScriptableInputStream);
        scriptableInputStream.init(aStream);
        this._myData += scriptableInputStream.read(aLength);
      }});
  	},
  
	QueryInterface: function(aIID)
	{
		if (!aIID.equals(nsIglPHProxy) &&
		!aIID.equals(nsISupports)&& 
    	!aIID.equals(CI.nsIObserver))
		throw Components.results.NS_ERROR_NO_INTERFACE;
		return this;
	}
};
var PHProxyFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new PHProxy()).QueryInterface(aIID);
  }
};

var PHProxyModule = {
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, 
        CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType)
  {
    aCompMgr = aCompMgr.
        QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return PHProxyFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};
function NSGetModule(aCompMgr, aFileSpec) { return PHProxyModule; }